﻿/*
=== Design Patterns ===
= Functionele Decompositie = 
Grote problemen ontbinden in kleine functionele stappen.

Problemen Functionele Decompositie:
- Creëert ontwerp met gecentraliseerd hoofdprogramma
- Creëert ontwerp dat niet snel op veranderingen reageert.
Hoe ontstaan deze problemen:

- Slecht gebruik van Abstraction
- Slechte encapsulation
- slechte modularity
 
= Software Analyse =
- Voor de ontwerpfase
- Als reactie op een wijzigingsverzoek gedurende de onderhoudsfase van een bestaand systeem.
Hoofdvraag:
- Wat is het probleem at opgelost dient te worden?
 
= Software ontwerp = 
- Na de analysefase
Hoofdvraaag:
- hoe ga ik het probleem oplossen?
 
= Requirements =
- Tijdens Analysefase:
- Eenvoudige,duidelijke en scherpe uitspraken van gewenste functionele en non functionele mogelijkheden en van de beperkingen waaraan moet worden voldaan.

Problemen van requirements:
- Scope
- Interpretatie
- Stabiliteit (veranderende requirements en technologie)

= Opsplitsen van modules =
- Inkapseling
    - Verberg interne details
    - Communiceer alleen via goed gedefinieerde interfaces
    - Isoleer moeilijke ontwerpbeslissingen
- Modularisatie
    - Mogelijk herbruikbaar in andere applicaties
    - Manipuleren niet meer dan 1 datastructuur
- Lage koppeling en hoge cohesie
    - Koppeling: De mate waarin twee modulen van elkaar afhankelijk zijn
    - Cohesie: De mate waarin de elementen in 1 module functioneel verbonden zijn
 

Een pattern omschrijft een (in de praktijk) vaak optredend probleem en de oplossing hiervan.
Creational patterns = Design patterns die te maken hebben met object creatie.
Structural patterns = Design patterns die het makkelijk maken relaties tussen elementen aan
te maken.
Behavioral patterns = Design patterns die gemeenschappelijke communicatie tussen objecten
identificeren.
 
 
1. Singleton (Creational pattern)
Een singleton zorgt ervoor dat er altijd één en slechts één instantie van een bepaald object
bestaat, en zorgt voor een globaal toegangspunt.
Voordelen
- Verhoogd Veiligheid
- Netter dan globale static variabelen
- Singleton kan gesubclassed worden

Nadelen
- Object wordt nooit verwijderd

2. Strategy (Behavioral pattern)
Verschillende actieklassen die je dynamisch op runtime kan toewijzen aan de
contextklassen.
Je gebruikt het Strategy pattern wanneer je verschillende acties dynamisch
moet toewijzen aan verschillende context objecten. Een voorbeeld hiervan is het toewijzen
van verschillende soorten “Sprongen” aan verschillende “Karakters”. Een normale sprong aan
een speler en een hoge sprong aan een vijand. Hierbij worden twee verschillende sprong
objecten gemaakt: “Hoge sprong” en “Normale sprong” die allebei overerven van een IJumpStrategy

3. Observer (Behavioral pattern)
Het observer pattern geeft toestandsveranderingen door aan andere objecten zonder dat de
objecten sterk gekoppeld zijn. Het observer pattern kan goed worden gebruikt als
(verschillende) views dynamisch gegevens moeten ontvangen wanneer deze worden
gewijzigd. Een voorbeeld hiervan is bij het maken van een applicatie die de beurskoersen
checkt. iedere keer dat één van de koersen veranderd zal de observer een update uitvoeren.
Deze update zorgt ervoor dat alle views de nieuwe aangepaste informatie bevatten.

Consequenties:
- Losse koppeling tussen subject en observer
- De update wordt gestuurd naar *alle* geïnteresseerden
- Elke wijziging in het subject levert een update van alle observers op

4. Decorator (Structural pattern)
Voeg op runtime verantwoordelijkheden toe aan een object zonder de classcode te
veranderen. Wordt gebruikt wanneer er verschillende objecten zijn die een combinatie zijn
van verschillende onderdelen. Bijvoorbeeld een pizza die bestaat uit verschillende
ingrediënten. Bij het voorbeeld van de pizza worden klassen gemaakt voor alle losse
ingrediënten en deze worden samengevoegd tot één geheel.
 
Consequenties:
- Verantwoordelijkheden kunnen ook op runtime veranderd worden.
- In plaats van klassen vol te laden met functionaliteit, voeg je functionaliteit in losse 
  klassen toe.
- Veel kleine klassen die op elkaar lijken waardoor moeilijk te begrijpen en debuggen
  
 
5. Command (Behavioral pattern)
Kan worden gebruikt wanneer je een verzoek wilt versturen maar niets wilt weten over de
inhoud van het verzoek of aan wie het verzoek wordt gedaan. hierdoor heb je een goede
scheiding tussen verzoeker en uitvoerder plus je hebt een support voor de “Undo”
functionaliteit. Het command pattern kan onder andere gebruikt worden bij een
afstandsbediening. De commando’s worden dan gekoppeld aan de knoppen van de
afstandbedieningen. Deze knoppen voeren de execute methode van het commando uit die op
zijn beurt de actie van de ontvanger uitvoert.
 
Consequenties:
- Commando ontkoppelt verstuurder(invoker) van de ontvanger(receiver)
- Commando’s zijn normale klassen, ze kunnen worden gemanipuleerd en uitgebreid
  zoals elk ander object
- Het is gemakkelijk nieuwe commando’s toe te voegen omdat bestaande klassen niet
  hoeven worden aangepast

6. Composite (Structural pattern)
Wanneer je geen verschil wilt maken tussen losse objecten en groepen van objecten dan kan
je het composite pattern gebruiken. Kan bijvoorbeeld worden gebruikt bij het groeperen van
muziek. Genres kunnen onder elkaar vallen en deze genres bevatten op hun beurt weer
verschillende muziek objecten.
 
Consequenties:
- Maakt het makkelijk nieuwe soorten componenten toe te voegen
- Maakt de client simpel, groepen en losse objecten kunnen als hetzelfde object worden beschouwd
- Creëert een hiërarchie van objecten.

7. Iterator (Behavioral pattern)
Het Iterator pattern kan worden gebruikt wanneer je door verzamelingen heen wilt lopen
zonder dat je weet watvoor verzameling het is. Op deze manier kan je in één methode door
verzamelingen als: arrays, arrayLists, hashmaps, LinkedLists, etc. lopen in plaats van
verschillende methodes voor de verschillende datastructuren. Hiervoor wordt een
IEnumerator gebruikt in C#.

8. Chain of responsibility (Behavioral pattern)
Wanneer je meerdere objecten een kans wilt geven een request af te ronden dan kan je het
chain of responsibility pattern gebruiken. Deze objecten kan je eenvoudig wijzigen, toevoegen
of je kan de volgorde ervan veranderen. Het chain of responsibility pattern kan bijvoorbeeld
gebruikt worden wanneer je verschillende niveaus van rechten hebt. Je hebt bijvoorbeeld een
manager, directeur en president. De manager mag niet meer dan 1000 euro betalen, de
directeur niet meer dan 10.000 en de president niet meer dan 100.000 euro. Om dit t
realiseren kan je gebruik maken van het chain of responsibility pattern.

9. Abstract Factory (Creational pattern)
Het doel van het Abstract Factory pattern is het vereenvoudigen van het onderhoud van het
programma. Als er nieuwe subklassen nodig zijn dan hoeft men alleen een nieuwe
factorymethode te implementeren. Een voorbeeld is de opmaak van een UI. Er zijn
verschillende soorten buttons en labels, namelijk moderne buttons en klassieke buttons. In de
concrete factories wordt bepaald welke van de twee stylen wordt gebruikt.

10. The principles of design patterns
SOLID
- Single Responsibility Principle
    Wanneer een klasse meer dan één afhankelijkheid heeft dan
    zijn er ook meer dan één redenen om deze klasse aan te passen.
 
- Open Closed Principle
    Klassen moeten open staan voor uitbreiding maar gesloten zijn voor
    aanpassingen; De deur openhouden voor het uitbreiden van de functionaliteit zonder de
    huidige source code te hoeven wijzigen.
 
- Liskov Substitution Principle
    Objecten van een programma moeten vervangbaar zijn door instanties van hun subtypes.
 
- Interface Segregation Principle
    Klassen moeten niet afhangen van een te dikke , niet
    cohesieve interfaces. Interfaces moeten afgebroken worden in goed samenhangende
    groepen waar iedere groep een specifieke cliënt bedient. Wanneer nieuwe requirements de
    reden zijn voor het uitbreiden/wijzigen van een interface, willen we niet dat nietverwante
    klassen gedwongen worden om onnodige methoden te implementeren.
 
- Dependency Inversion Principle
    Modules in een hoger niveau moeten niet afhangen van
    modules in een lager niveau maar van abstracties (Interfaces of abstracte klassen)

Rigidity(stijfheid) = moeilijk te wijzigen, wijzigingen hebben vaak neveneffecten en je hebt
geen idee over de impact van je wijziging

Fragility(kwetsbaarheid) = Iedere wijziging zorgt voor errors in verschillende plekken van de
software. Vaak hebben de plekken waarin errors zijn opgetreden geen conceptuele relatie
met de plaats van wijziging.

Immobility(Onbeweeglijkheid) = Moeilijk om een module van een ander project of van
hetzelfde project te hergebruiken. Vaak moeten afhankelijkheden van de gewenste module
meegenomen worden.

Viscosity(Taaiheid):
- Verschillende manieren om een wijziging aan te brengen
- Het is gemakkelijk het foute te doen en lastig om het goede te doen
- Ontwikkelomgeving is traag en efficient (Bijv. Compileertijd is erg lang waardoor “juiste
  wijzigingen” die te veel compileertijd eisen worden vermeden.)

Onnodige complexiteit = ontwerpelementen die onnodig zijn of anticiperen op veranderingen
in de toekomst die misschien nooit plaats zullen vinden.
 
Onnodige herhaling = Dezelfde code op twee plaatsen implementeren
 
Opacity = hoe moeilijk de module te begrijpen is. Door regelmatige aanpassingen wordt de
code overzichtig en onnodig ingewikkeld te begrijpen.

Dependency Injection = Een klasse mag geen andere klassen instantiëren, maar wel
afhangen van de klassen die erin worden geïnjecteerd.
Inversion of Control = Wanneer een object (klant) iets nodig heeft van een andere object
(provider), wordt de klant door de provider aangeroepen (inversie) in plaats van
andersom.(Flow of logic)
 */